/**********************************************************

@description:
*File Name:loader.c
*Author: ydx
*mail: yudongxiang93@163.com
*Create Time: Sat 31 May 2025 02:56:48 PM CST
**********************************************************/
__asm__(".code16gcc");
#include "loader.h"

boot_info_t boot_info;

const char messages[][64] __attribute__((section(".rodata"))) = {
    "-------loading-------\n\r",
    "-------detect memory-------\n\r",
    "-------detect memory failed-------\n\r",
    "-------detect memory success-------\n\r",
};

void show_msg(const char *msg)
{
    char c;
    while ((c = *msg++) != '\0')
    {
        __asm__ __volatile__("mov $0xe,%%ah\n\t"
                             "mov %[ch],%%al\n\t"
                             "int $0x10" ::[ch] "r"(c));
    }
}
static void detect_memory(void)
{
    uint32_t     signature;
    uint32_t     bytes;
    uint32_t     contID = 0;
    SMAP_entry_t smap_entry;
    show_msg(messages[1]);
    boot_info.ram_region_count = 0;
    for (int i = 0; i < BOOT_RAM_REGION_MAX; i++)
    {
        SMAP_entry_t *entry = &smap_entry;
        __asm__ __volatile__("int $0x15"
                             : "=a"(signature), "=c"(bytes), "=b"(contID)
                             : "a"(0xE820), "b"(contID), "c"(24), "d"(0x534D4150), "D"(entry));
        if (signature != 0x534D4150)
        {
            show_msg(messages[2]);
            return;
        }
        if (bytes > 20 && (entry->ACPI & 0x0001) == 0)
        {
            continue;
        }
        if (entry->Type == 1)
        {
            boot_info.ram_region_cfg[boot_info.ram_region_count].start = entry->BaseL;
            boot_info.ram_region_cfg[boot_info.ram_region_count].size  = entry->LengthL;
            boot_info.ram_region_count++;
        }
        if (contID == 0)
        {
            break;
        }
    }
    show_msg(messages[3]);
}
uint16_t gdt_table[][4] __attribute__((section(".data"))) = {
    {0, 0, 0, 0},
    {0xFFFF, 0x0000, 0x9A00, 0x00CF},
    {0xFFFF, 0x0000, 0x9200, 0x00CF},
    {0xFFFF, 0x0000, 0xFA00, 0x00CF},
    {0xFFFF, 0x0000, 0xF200, 0x00CF},
};
static void enter_protected_mode(void)
{
    cli();
    // open A20
    uint8_t v = inb(0x92);
    outb(0x92, v | 0x02);
    // load gdt
    lgdt((uint32_t)&gdt_table, sizeof(gdt_table));
    // set cr0->PE=1
    uint32_t cr0 = read_cr0();
    write_cr0(cr0 | (1 << 0));
    // clear instruction pipline
    far_jump(8, (uint32_t)protect_mode_entry);
}
void loader_entry(void)
{
    show_msg(messages[0]);
    detect_memory();
    enter_protected_mode();
    for (;;)
    {
    }
}
